package com.uw.uwrpc.core.provider.invoker;

import com.uw.uwrpc.core.api.RpcContext;
import com.uw.uwrpc.core.api.RpcRequest;
import com.uw.uwrpc.core.api.RpcResponse;
import com.uw.uwrpc.core.exception.RpcException;
import com.uw.uwrpc.core.util.SlidingTimeWindow;
import com.uw.uwrpc.core.meta.ProviderMeta;
import com.uw.uwrpc.core.provider.ProviderBootstrap;
import com.uw.uwrpc.core.provider.ProviderInvoker;
import com.uw.uwrpc.core.util.MethodUtil;
import com.uw.uwrpc.core.util.TypeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Slf4j
public class ReflectProviderInvoker implements ProviderInvoker {


    private final ProviderBootstrap providerBootstrap;

    private final Map<String, SlidingTimeWindow> windowMap = new HashMap<>();

    public ReflectProviderInvoker(ProviderBootstrap providerBootstrap) {
        this.providerBootstrap = providerBootstrap;
    }

    public RpcResponse<?> invoke(RpcRequest rpcRequest) {
        try {
            log.debug(" ===> ReflectProviderInvoker.invoke(request:{})", rpcRequest);
            // 跨调用方需要传递的参数
            RpcContext.getContextParam().putAll(rpcRequest.getParameters());
            // 忽略Object的方法
            String service = rpcRequest.getService();
            if (MethodUtil.checkObjectMethod(rpcRequest.getMethodSign())) {
                return RpcResponse.fail(new RpcException(String.format("%s#%s not allow method.", service, rpcRequest.getMethodSign())));
            }
            // 查找对应的 api
            Optional<ProviderMeta> providerMetaOpt = findProviderMeta(rpcRequest);
            if (providerMetaOpt.isEmpty()) {
                return RpcResponse.fail(new RpcException(String.format("%s#%s not found", service, rpcRequest.getMethodSign())));
            }
            // 流控限制
            if(!providerBootstrap.getTrafficControl().allow(rpcRequest)) {
                return RpcResponse.fail(new RpcException("service " + service + " is overload"));
            }


            ProviderMeta providerMeta = providerMetaOpt.get();
            // 获取参数类型。
            List<Class<?>> parameterClassList = MethodUtil.getParameterClass(providerMeta.getMethodSign());
            // 将参数按照方法签名的参数类型进行转换。
            Object[] args = TypeUtil.cast(rpcRequest.getArgs(), parameterClassList);
            // 反射调用对应的 api。
            Object invoke = providerMeta.getMethod().invoke(providerMeta.getServiceImpl(), args);
            return RpcResponse.success(invoke);
        } catch (InvocationTargetException e) {
            return RpcResponse.fail(new RpcException(e.getTargetException().getMessage()));
        } catch (IllegalAccessException e) {
            return RpcResponse.fail(new RpcException(e.getMessage()));
        } catch (Exception e) {
            return RpcResponse.fail(new RpcException(e.getMessage()));
        } finally {
            // 清理请求上下文，避免影响下一次调用。
            RpcContext.clearContext();
        }
    }

    public Optional<ProviderMeta> findProviderMeta(RpcRequest rpcRequest) {
        List<ProviderMeta> providerMetaList = providerBootstrap.getSkeleton().get(rpcRequest.getService());
        if (CollectionUtils.isEmpty(providerMetaList)) {
            return Optional.empty();
        }

        return providerMetaList.stream().filter(e -> e.getMethodSign().equals(rpcRequest.getMethodSign())).findFirst();
    }
}
